﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Sustainalytics.Controversies.BusinessLogic;
using Sustainalytics.DataLayer;
using Sustainalytics.DataLayer.Exceptions.AccountsAndUsers;
using Sustainalytics.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace Sustainalytics.Accounts.BusinessLogic.Tests
{
    [TestClass]
    public class AccountWithIpManagerTest
    {
        private static Mock<IPlainBl<AccountIpAuthentication>> _mockPAccountIpAuth;
        private static Mock<IUserIpLoginManager> _mockUserBl;
        private static Mock<IAccountsRepository> _mockAccountRepository;
        private static AccountWithIpManager _manager;
        private static Mock<IIpDataCheck> _mockDataCheck;

        [ClassInitialize]

            public static void InitClass(TestContext context, Mock<IPlainBl<AccountIpAuthentication>> mockPAccountIpAuth, Mock<IUserIpLoginManager> mockUserBl,
                                                 Mock<IAccountsRepository> mockAccountRepository, AccountWithIpManager manager, Mock<IIpDataCheck> mockDataCheck)
       {
           _mockPAccountIpAuth = mockPAccountIpAuth;
           _mockUserBl = mockUserBl;
           _mockAccountRepository = mockAccountRepository;
            _mockDataCheck = mockDataCheck;
           _manager = manager;
       }
       

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void CreateOrUpdate_ShouldReturnfalse_accountip_is_empty()
        {
            _manager.CreateOrUpdate(new AccountIpAuthentication());
            _mockPAccountIpAuth.Verify(a => a.CreateOrUpdate(It.IsAny<AccountIpAuthentication>()), Times.Never);
        }

        [TestMethod]
        public void CreateOrUpdate_ShouldReturnTrue_account_valid_call_user_from_the_account_id()
        {
            var guidAccount = Guid.Parse("855db0f3-b52e-4cdc-a5b4-e783fd54d8b2");
            var guidUser = Guid.Parse("92b1e375-9982-4e72-b3d7-2276b84f06f8");
            var obj = new AccountIpAuthentication()
            {
                Id = guidAccount,
                IpDatas = new List<IpData>() { new IpData("10.0.0.1", "") },
                Status = Status.Active
            };
            _mockPAccountIpAuth.Setup(a => a.ReadAllWhere(It.IsAny<Expression<Func<AccountIpAuthentication, bool>>>(), null, null))
                .Returns(new List<AccountIpAuthentication>()
                    {
                        new AccountIpAuthentication()
                        {
                            Id =Guid.Empty
                        }
                    });
            _mockUserBl.Setup(a => a.GetFakeUserIp(guidAccount, It.IsAny<string>(), It.IsAny<string>())).Returns(new User() { Id = guidUser, FirstName = "TestIp" });
            var output = _manager.CreateOrUpdate(obj);
            Assert.IsTrue(output);
            _mockUserBl.Verify(a => a.GetFakeUserIp(guidAccount, It.IsAny<string>(), It.IsAny<string>()));
            _mockPAccountIpAuth.Verify(a => a.CreateOrUpdate(It.Is<AccountIpAuthentication>(d => d.Id == guidAccount && d.UserId == guidUser)));
        }

        [TestMethod]
        [ExpectedException(typeof(AccountNotFoundException))]
        public void CreateOrUpdate_ShouldThrowException_account_sent_was_not_found_account_collection()
        {
            var guidAccount = Guid.Parse("855db0f3-b52e-4cdc-a5b4-e783fd54d8b2");

            _mockAccountRepository.Setup(a => a.GetAccountById(guidAccount)).Returns(default(Account));
            var obj = new AccountIpAuthentication()
            {
                Id = guidAccount,
                IpDatas = new List<IpData>() { new IpData("10.0.0.1", "") },
                Status = Status.Active
            };
            _manager.CreateOrUpdate(obj);
        }

        [TestMethod]
        [ExpectedException(typeof(IpAccountOverlapingException))]
        public void CreateOrUpdate_ShouldThrowException_account_sent_with_overlaping_ip()
        {
            var guidAccount = Guid.Parse("855db0f3-b52e-4cdc-a5b4-e783fd54d8b2");
            _mockDataCheck.Setup(a => a.GetIpAuthenticationIntersections(It.IsAny<AccountIpAuthentication>()))
                .Returns(Enumerable.Range(0, 3).Select(a => new AccountIpAuthentication() { Id = Guid.NewGuid() }).ToArray());
            var obj = new AccountIpAuthentication()
            {
                Id = guidAccount,
                IpDatas = new List<IpData>() { new IpData("10.0.0.1", "") },
                Status = Status.Active
            };
            _manager.CreateOrUpdate(obj);
        }

        [TestMethod]
        public void CreateOrUpdate_ReturnTrue_AccountExistsWithIpAdressAdded_ButWereRemovedFromUI_DeleteFakeUserIp()
        {
            var guidAccount = Guid.Parse("855db0f3-b52e-4cdc-a5b4-e783fd54d8b2");
            var guidUser = Guid.Parse("92b1e375-9982-4e72-b3d7-2276b84f06f8");
            var obj = new AccountIpAuthentication()
            {
                Id = guidAccount,
                IpDatas = new List<IpData>(),
                Status = Status.Active
            };
            _mockPAccountIpAuth.Setup(d => d.ReadAllWhere(It.IsAny<Expression<Func<AccountIpAuthentication, bool>>>(), null, null))
                .Returns(new List<AccountIpAuthentication>()
                {
                    new AccountIpAuthentication()
                    {
                        Id = guidAccount,
                        IpDatas = new List<IpData>() {new IpData("10.0.0.1", "")},
                        Status = Status.Active,
                        UserId = guidUser,
                    }
                });
            _mockUserBl.Setup(a => a.DeleteFakeUserIpData(guidUser)).Returns(true);
            _mockUserBl.Setup(a => a.GetFakeUserIp(guidAccount, It.IsAny<string>(), It.IsAny<string>())).Returns(new User() { Id = guidUser, FirstName = "TestIp" });
            var output = _manager.CreateOrUpdate(obj);
            Assert.IsTrue(output);
            _mockPAccountIpAuth.Verify(d => d.ReadAllWhere((It.IsAny<Expression<Func<AccountIpAuthentication, bool>>>()), null, null));
            _mockUserBl.Verify(a => a.DeleteFakeUserIpData(guidUser));
            _mockPAccountIpAuth.Verify(a => a.CreateOrUpdate(It.Is<AccountIpAuthentication>(d => d.Id == guidAccount && d.UserId == Guid.Empty && d.UserName == String.Empty)));
            _mockUserBl.Verify(a => a.GetFakeUserIp(It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<string>()), Times.Never);
        }

        [TestMethod]
        public void CreateOrUpdate_ReturnTrue_AccountExistedHadNoIpEntries_NewFakeUserNeedsToBeCreated()
        {
            var guidAccount = Guid.Parse("855db0f3-b52e-4cdc-a5b4-e783fd54d8b2");
            var guidUser = Guid.Parse("92b1e375-9982-4e72-b3d7-2276b84f06f8");
            var obj = new AccountIpAuthentication()
            {
                Id = guidAccount,
                IpDatas = new List<IpData>() { new IpData("10.0.0.1", "") },
                Status = Status.Active
            };
            _mockPAccountIpAuth.Setup(d => d.ReadAllWhere(It.IsAny<Expression<Func<AccountIpAuthentication, bool>>>(), null, null))
                .Returns(new List<AccountIpAuthentication>()
                {
                    new AccountIpAuthentication()
                    {
                        Id = guidAccount,
                        IpDatas = new List<IpData>() ,
                        Status = Status.Active,
                    }
                });
            _mockUserBl.Setup(a => a.DeleteFakeUserIpData(guidUser)).Returns(true);
            _mockUserBl.Setup(a => a.GetFakeUserIp(guidAccount, It.IsAny<string>(), It.IsAny<string>())).Returns(new User() { Id = guidUser, FirstName = "TestIp" });
            _manager.CreateOrUpdate(obj);
            _mockPAccountIpAuth.Verify(d => d.ReadAllWhere((It.IsAny<Expression<Func<AccountIpAuthentication, bool>>>()), null, null));
            _mockUserBl.Verify(a => a.GetFakeUserIp(guidAccount, It.IsAny<string>(), It.IsAny<string>()));
            _mockPAccountIpAuth.Verify(a => a.CreateOrUpdate(It.Is<AccountIpAuthentication>(d => d.Id == guidAccount && d.UserId == guidUser && !string.IsNullOrEmpty(d.UserName))));
        }

        [TestCleanup]
        public void Cleaning()
        {
            _mockAccountRepository.ResetCalls();
            _mockUserBl.ResetCalls();
            _mockPAccountIpAuth.ResetCalls();
            _mockDataCheck.ResetCalls();

            _mockPAccountIpAuth.Setup(a => a.CreateOrUpdate(It.IsAny<AccountIpAuthentication>())).Returns(true);
            _mockAccountRepository.Setup(a => a.GetAccountById(It.IsAny<Guid>()))
                .Returns(new Account() { Id = Guid.NewGuid() });
        }
    }
}
